home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Linux Cubed Series 8: LINUX Games
/
Linux Cubed Series 8 - LINUX Games.iso
/
games
/
x11
/
strategy
/
xpat2-1.000
/
xpat2-1
/
xpat2-1.04
/
src
/
rules.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-09-28
|
10KB
|
361 lines
/*****************************************************************************/
/* */
/* */
/* X patience version 2 -- module rules.c */
/* */
/* General utility functions for all rule sets */
/* written by Heiko Eissfeldt and Michael Bischoff */
/* see COPYRIGHT.xpat2 for Copyright details */
/* */
/* */
/*****************************************************************************/
#include "xpatgame.h"
#include <time.h>
Cardindex complete_suit(Pileindex pile, Cardindex i) {
Rank r;
Suit s;
int c;
if (IS_JOKER(game.cards[i]))
return 0;
r = RANK(game.cards[i]);
s = SUIT(game.cards[i]);
if (r != Ace)
return 0;
for (c = rules.cards_per_color-1; c > 0; --c) {
if (--i < game.ind[pile] || !game.visible[i])
return -1;
if (RANK(game.cards[i]) != ++r || SUIT(game.cards[i]) != s)
return -1;
}
return i;
}
/* Move cards to stack. */
int stackable(Pileindex pile) {
if (rules.stackable) {
return (*rules.stackable)(pile);
} else {
Cardindex srcindex;
srcindex = INDEX_OF_LAST_CARD(pile);
switch (rules.move_bits & ST_MASK) {
case ST_NONE:
return -1; /* user may not may cards to stack */
case ST_ONE:
if (IS_JOKER(game.cards[srcindex])) /* jokers not movable to stack */
return -1;
break;
case ST_13:
if ((srcindex = complete_suit(pile, srcindex)) == -1)
return -1;
break;
}
return srcindex;
}
}
int move_to_stack(Pileindex pile) { /* pile is slot or tmp */
Cardindex srcindex;
Pileindex i;
if (EMPTY(pile))
return 0;
if ((srcindex = stackable(pile)) == -1)
return 0;
for (i = 0; i < rules.numstacks; ++i) {
if (SUIT(i) != SUIT(game.cards[srcindex]))
continue;
if (move_valid(srcindex, i)) {
store_move(do_move(srcindex, i));
return 1;
}
}
return 0;
}
void check_win_game(void) {
if (game.finished)
return; /* don't win twice */
if (rules.game_won) {
if (!(*rules.game_won)())
return;
} else {
if (game.ind[FIRST_SLOT] != rules.cards_per_color * rules.numstacks)
return;
}
/* actually, win the game! */
/* all cards on the stacks and not yet notified */
game.finished = True;
write_log_file();
show_message(TXT_YOU_WIN); /* overwrites OK */
win_game(); /* hook for additional doodads */
play_sound("success");
}
int in_relaxed_sequence(int srccard, int dstcard) {
if (rules.relaxed_valid)
return (*rules.relaxed_valid)(srccard, dstcard);
switch (rules.move_bits & US_MASK) {
case US_RS:
if (IS_JOKER(dstcard) || IS_JOKER(srccard))
return 1;
return RANK(dstcard) == 1 + RANK(srccard) && SUIT(dstcard) == SUIT(srccard);
case US_R:
if (IS_JOKER(dstcard) || IS_JOKER(srccard))
return 1;
return RANK(dstcard) == 1 + RANK(srccard);
case US_RA:
if (IS_JOKER(dstcard) || IS_JOKER(srccard))
return 1;
return RANK(dstcard) == 1 + RANK(srccard) && DIFFERENT_COLOR(dstcard, srccard);
}
return 0;
}
int in_strong_sequence(int srccard, int dstcard) {
if (rules.valid)
return (*rules.valid)(srccard, dstcard);
switch (rules.move_bits & MG_MASK) {
case MG_RS:
if (IS_JOKER(dstcard) || IS_JOKER(srccard))
return 1;
return RANK(dstcard) == 1 + RANK(srccard) && SUIT(dstcard) == SUIT(srccard);
case MG_R:
if (IS_JOKER(dstcard) || IS_JOKER(srccard))
return 1;
return RANK(dstcard) == 1 + RANK(srccard);
case MG_RA:
if (IS_JOKER(dstcard) || IS_JOKER(srccard))
return 1;
return RANK(dstcard) == 1 + RANK(srccard) && DIFFERENT_COLOR(dstcard, srccard);
}
return 0;
}
/* find maximum sequence in a nonempty slot for moving */
Cardindex slotsequence(Pileindex ind, Cardindex start, Cardindex stop) {
while (start > game.ind[ind] && game.visible[start-1] && start != stop &&
in_strong_sequence(game.cards[start], game.cards[start-1]))
--start;
return start;
}
/* find maximum sequence in a nonempty slot for moving */
Cardindex relaxedslotsequence(Pileindex ind, Cardindex start, Cardindex stop) {
while (start > game.ind[ind] && game.visible[start-1] && start != stop &&
in_relaxed_sequence(game.cards[start], game.cards[start-1]))
--start;
return start;
}
int default_movevalid(Cardindex src, Pileindex dstpile) {
int srcpile, dstcard, srccard;
srcpile = getpile(src);
if (srcpile == dstpile)
return 0;
switch (game.piletype[srcpile]) { /* filter out some invalid sources */
case FacedownDeck:
return 0;
case Stack:
if (!(rules.move_bits & STACK_SOURCE))
return 0;
break;
case FaceupDeck: /* always valid sources */
case Tmp:
case Slot:
break;
}
dstcard = EMPTY(dstpile) ? -1 : game.cards[game.ind[dstpile+1]-1];
srccard = game.cards[src];
switch (game.piletype[dstpile]) {
case Stack:
if (SUIT(dstpile) != SUIT(game.cards[src]))
return 0;
if (rules.stackable) {
if (src != (*rules.stackable)(srcpile))
return 0; /* not possible to move to stack */
} else {
switch (rules.move_bits & ST_MASK) {
case ST_NONE:
return 0; /* user may not may cards to stack */
case ST_ONE:
if (src != INDEX_OF_LAST_CARD(srcpile) || IS_JOKER(game.cards[src]))
return 0;
break;
case ST_13:
if (src != complete_suit(srcpile, INDEX_OF_LAST_CARD(srcpile)))
return 0;
break;
}
}
/* src is a block of cards without jokers */
if (RANK(game.cards[INDEX_OF_LAST_CARD(srcpile)]) != (
dstcard == -1 ? Ace : (1 + RANK(dstcard)) ))
return 0;
/* top cards match */
return 1;
case Slot:
if (dstcard == -1) {
switch (rules.move_bits & ES_MASK) {
case ES_KINGS: /* Klondike: only Kings are */
if (IS_JOKER(game.cards[src]) || RANK(game.cards[src]) == King)
return 1;
break;
case ES_ALL:
return 1;
}
} else { /* move to non-empty slot */
return in_relaxed_sequence(srccard, dstcard);
}
return 0; /* fall through: move not allowed */
case Tmp:
if (game.ind[srcpile+1] - src != 1)
return 0; /* only one card can be moved */
return dstcard == -1;
default:
return 0;
}
}
int debugging = 0;
int move_valid(Cardindex src, Pileindex dstpile) {
if (debugging)
return 1;
if (rules.movevalid)
return (*rules.movevalid)(src, dstpile);
else
return default_movevalid(src, dstpile);
}
Cardindex maxsequence(Pileindex ind, Cardindex cardi) {
if (!EMPTY(ind)) { /* the pile may not be empty for this operation */
switch (game.piletype[ind]) {
case Stack:
if (!(rules.move_bits & STACK_SOURCE))
break; /* not allowed => break */
/* fall through: */
case Tmp:
return INDEX_OF_LAST_CARD(ind);
case Slot:
return slotsequence(ind, INDEX_OF_LAST_CARD(ind), cardi);
case FaceupDeck:
if (rules.variant & DECK_SOURCE)
return INDEX_OF_LAST_CARD(ind);
break; /* not allowed => fall through */
case FacedownDeck:
if ((rules.variant & DECK_VISIBLE) && !EMPTY(ind))
return INDEX_OF_LAST_CARD(ind);
break;
}
}
return -1; /* this indicates that selection is not possible */
}
/* check, if new cards may be dealt */
int check_new_cards(void) {
Pileindex i;
Cardindex (*testfunc)(Pileindex, Cardindex, Cardindex) = NULL;
if (rules.variant&NODEAL)
return 0;
if (rules.new_cards)
return (*rules.new_cards)(); /* custom function */
if (!CARDS_ON_PILE(IDECK))
return 0; /* no more cards */
switch (rules.move_bits & DC_MASK) {
case DC_ALWAYS:
return 1;
/* case DC_NOEMPTY: falls thru */
case DC_STRONGOK:
testfunc = slotsequence;
break;
case DC_RELAXEDOK:
testfunc = relaxedslotsequence;
break;
}
for (i = FIRST_SLOT; i <= LAST_SLOT; ++i)
if (EMPTY(i))
goto require_check;
return 1; /* no empty slot */
require_check:
if (!testfunc)
return 0;
/* may give cards if all nonempty slots are in some sequence */
for (i = FIRST_SLOT; i <= LAST_SLOT; ++i)
if (!EMPTY(i))
if ((*testfunc)(i, INDEX_OF_LAST_CARD(i), INDEX_OF_FIRST_CARD(i))
!= INDEX_OF_FIRST_CARD(i))
return 0; /* test failed, pile unsorted */
return 1; /* OK, all nonempty pile are in order */
}
int std_good_hint(Cardindex srcindex, Pileindex dstpile) {
Pileindex srcpile = getpile(srcindex);
int value = 0;
if (IS_STACK(srcpile)) /* don't move from stack if not explicitly requested */
value = 1;
else if (IS_STACK(dstpile)) { /* likes to move cards to stack */
value = (rules.variant & ST_MASK) == ST_13 ? 10000 : 30;
} else
value = 15; /* value of standard move */
/* modifications */
if (IS_SLOT(dstpile)) {
switch (rules.move_bits & MG_MASK) {
case MG_RS:
if (SUIT(game.cards[srcindex]) == SUIT(game.cards[INDEX_OF_LAST_CARD(dstpile)]))
value += 15;
else if (RANK(game.cards[srcindex]) == RANK(game.cards[srcindex-1]) - 1)
value -= 15;
else
value += RANK(game.cards[srcindex]); /* higher ones first */
break;
case MG_NONE:
if (RANK(game.cards[srcindex]) == RANK(game.cards[srcindex-1]) - 1)
value -= 15; /* doesn't make anything better */
else
value -= 10;
break;
}
}
if (IS_SLOT(srcpile)) {
if (game.ind[srcpile] == srcindex) {
/* bonus for creating empty space */
switch (rules.move_bits & ES_MASK) {
case ES_NONE:
value -= 10; /* no bonus */
break;
case ES_KINGS:
value += 10;
break;
case ES_ALL:
value += 100;
break;
}
} else if (!game.visible[srcindex-1]) {
/* turn a card */
value += 10;
}
}
if (value < 1)
value = 1;
return value;
}